﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Oracle.DataAccess.Client;
using Oracle.DataAccess.Types;
using System.Data;


namespace GestionCegep.Objects
{
    public class Inscription : PersistentObject
    {
        private static Inscription oldInscription = new Inscription();

        // Différentes requetes a la base de donnees pour la gestion des inscriptions
        private const string selectQuery = "SELECT ID, ID_COURS, ETUDIANT, ID_COURS, DATE_INSCRIPTION FROM INSCRIPTION";
        private const string lockQuery = "LOCK TABLE INSCRIPTION IN EXCLUSIVE MODE";
        private const string insertQuery = "INSERT INTO INSCRIPTION(ETUDIANT, ID_COURS) VALUES({0}, {1}) RETURNING ID INTO :myOutputParameter";
        private const string updateQuery = "UPDATE INSCRIPTION SET ETUDIANT = {1}, ID_COURS = {2} WHERE ID = {0}";
        private const string deleteQuery = "DELETE FROM INSCRIPTION WHERE ID = {0}";

        private int id;                 // ID de l'inscription
        private Etudiant etudiant;      // Etudiant inscrit à un cours
        private Cours cours;            // Cours auquel est inscrit l'etudiant
        private DateTime date;          // Date et heure a laquelle l'etudiant s'est inscrit

        // Constructeur
        private Inscription(int id, Etudiant etudiant, Cours cours, DateTime date, bool isNew = false)
        {
            this.id = id;
            this.etudiant = etudiant;
            this.cours = cours;
            this.date = date;
            this.isNew = isNew;
        }

        public Inscription()
        {
            isNew = true;
        }

        public Inscription(int id, Etudiant etudiant, Cours cours)
        {
            this.id = id;
            this.etudiant = etudiant;
            this.cours = cours;
            this.date = DateTime.Now;
            this.isNew = true;
        }

        public int Id { get { return id; } set { id = value; } }
        public Etudiant Etudiant { get { return etudiant; } set { etudiant = value; } }
        public Cours Cours { get { return cours; } set { cours = value; } }
        public DateTime Date { get { return date; } }

        // Insertion dans la base de donnees
        public override void InsertIntoDataBase(OracleConnection OracleConnection, DataStore dataStore)
        {
            OracleDecimal ora_dec;
            OracleCommand command;
            string coursSigle = cours != null ? cours.Sigle : string.Empty;
            string etudiantMatricule = etudiant != null ? etudiant.Matricule : string.Empty;
            try
            {
                command = OracleConnection.CreateCommand(); // Creation de la commande Oracle
                command.CommandText = lockQuery; // Verouillage de la table
                command.ExecuteNonQuery();


                command.CommandText = String.Format(insertQuery, "NULL", "NULL");
                command.Parameters.Add("myOutputParameter", OracleDbType.Decimal, ParameterDirection.ReturnValue);
                command.ExecuteNonQuery();

                // Recuperation du dernier ID d'inscription inserer dans la base de donnees
                ora_dec = (OracleDecimal)command.Parameters["myOutputParameter"].Value;
                id = ora_dec.ToInt32();

                // Journalisation des modifications
                dataStore.CurrentTransaction.PushLogToBD(LogActions.Defaire, String.Format(deleteQuery, id));
                dataStore.CurrentTransaction.PushLogToBD(LogActions.Refaire, String.Format(insertQuery, "NULL", "NULL"));

                dataStore.CurrentTransaction.Commit(); // Confirmation de la transaction
                this.date = DateTime.Now;
                dataStore.Inscriptions.Add(this); // Ajout de l'inscription a la liste des inscriptions
            }
            catch (OracleException exception)
            {
                throw exception;
            }
        }

        // Vérouillage pour la mise a jour
        public override void LockForUpdate(OracleConnection OracleConnection)
        {
            try
            {
                OracleCommand command = OracleConnection.CreateCommand(); // Creation de la commande
                command.CommandText = selectQuery + " WHERE ID = '" + id + "' FOR UPDATE"; // Vérouillage pour la mise a jour
                command.ExecuteScalar();

                oldInscription.id = id;
                oldInscription.etudiant = etudiant;
                oldInscription.cours = cours;
            }
            catch (OracleException exception)
            {
                throw exception;
            }
        }

        // Mise a jour dans la base de donnees
        public override void UpdateIntoDataBase(MyOracleTransaction currentTransaction)
        {
            string coursSigle = cours != null ? "'" + cours.Sigle.ToString() + "'" : "NULL";
            string etudiantMatricule = etudiant != null ? "'"+etudiant.Matricule.ToString()+ "'" : "NULL";
            try
            {
                OracleCommand command = currentTransaction.Connection.CreateCommand(); // Creation de la commande
                command.CommandText = String.Format(updateQuery, id, etudiantMatricule, coursSigle); // Mise a jour dans la base de donnees
                command.ExecuteNonQuery();

                // Journalisation des modifications
                coursSigle = oldInscription.cours != null ? "'" + oldInscription.cours.Sigle.ToString() + "'" : "NULL";
                etudiantMatricule = oldInscription.etudiant != null ? "'" + oldInscription.etudiant.Matricule.ToString() + "'" : "NULL";

                currentTransaction.PushLogToBD(LogActions.Defaire, String.Format(updateQuery, oldInscription.id, etudiantMatricule, coursSigle));
                currentTransaction.PushLogToBD(LogActions.Refaire, command.CommandText);

                currentTransaction.Commit(); // Confirmation de la transaction
            }
            catch (OracleException exception)
            {
                etudiant = oldInscription.etudiant;
                cours = oldInscription.cours;
                throw exception;
            }
        }

        // Suppression de la base de données
        public override void DeleteFromDataBase(OracleConnection OracleConnection, DataStore dataStore)
        {
            string coursSigle = cours != null ? cours.Sigle.ToString() : "NULL";
            string etudiantMatricule = etudiant != null ? etudiant.Matricule.ToString() : "NULL";
            OracleCommand command;
            try
            {
                command = OracleConnection.CreateCommand(); // Creation de la commande
                command.CommandText = lockQuery; // Verouillage de la table
                command.ExecuteNonQuery();

                command.CommandText = String.Format(deleteQuery, id); // Suppression de l'inscription de la base de données
                command.ExecuteNonQuery();

                // Journalisation des modifications
                string insertQuery = "INSERT INTO INSCRIPTION VALUES('{0}',{1},'{2}')";
                dataStore.CurrentTransaction.PushLogToBD(LogActions.Defaire, String.Format(insertQuery, id, etudiantMatricule, coursSigle));
                dataStore.CurrentTransaction.PushLogToBD(LogActions.Refaire, command.CommandText);

                dataStore.CurrentTransaction.Commit(); // Confirmation de la transaction
                dataStore.Inscriptions.Remove(this); // On retire l'inscription de la liste des inscriptions
            }
            catch (OracleException exception)
            {
                throw exception;
            }
        }

        // Balayage de la table Inscription pour obtenir toutes les informations
        public static List<Inscription> GetInscriptionsFromDataBase(OracleConnection OracleConnection, List<Etudiant> etudiants, List<Cours> lesCours)
        {
            List<Inscription> inscriptions = new List<Inscription>(); // Liste des inscriptions
            string coursSigle;
            Cours cours;

            string etudiantMatricule;
            Etudiant etudiant;

            try
            {
                OracleCommand command = OracleConnection.CreateCommand(); // Creation de la commande Oracle
                command.CommandText = selectQuery;
                OracleConnection.Open(); // Ouverture de la connexion
                OracleDataReader reader = command.ExecuteReader(); // Execution de la requete select

                // Tant qu'il y a des donnees dans la table Inscription
                while (reader.Read())
                {
                    coursSigle = reader["ID_COURS"].ToString();
                    if (!String.IsNullOrEmpty(coursSigle))
                        cours = lesCours.First(c => coursSigle.Equals(c.Sigle.ToString()));
                    else
                        cours = null;
                    etudiantMatricule = reader["ETUDIANT"].ToString();
                    if (!String.IsNullOrEmpty(etudiantMatricule))
                        etudiant = etudiants.First(e => etudiantMatricule.Equals(e.Matricule.ToString()));
                    else
                        etudiant = null;
                    Inscription inscription = new Inscription(Convert.ToInt32(reader["ID"].ToString()),
                                                                etudiant,
                                                                cours,
                                                                Convert.ToDateTime(reader["DATE_INSCRIPTION"].ToString()));
                    inscriptions.Add(inscription); // Ajout de tout les etudiants a la liste des etudiants
                }
                OracleConnection.Close(); // Fermeture de la connexion
            }
            catch (OracleException exception)
            {
                throw exception;
            }

            return inscriptions; // On retourne les inscriptions pour le remplissable du DataGridView
        }
    }
}
